package com.robot.console.util;

import java.math.BigInteger;
import java.util.Random;

public class RSA
{
	private BigInteger pub_key = new BigInteger("a3e102c4c1b4a703db140ca3fe3983b1", 16); // BigInteger.ZERO;
	private BigInteger pri_key = new BigInteger("437ac4e79b0e26a6917e79c26815632d", 16); // BigInteger.ZERO;
	private static BigInteger e = BigInteger.valueOf(17);
	// private static int chunk_size = 7; // (chunk_size + 2) must less than 64
	// / 8
	private static int chunk_size = 16; // (chunk_size + 2) must less than 64 /
	// 8
	private static String cipher_delimiter = "l"; // l letter
	private static int radix = 16;
	private String hashKey = "";

	public void genKeyPair()
	{
		int keysize = LibRSA.keys.length;
		Random r = new java.util.Random(System.currentTimeMillis());
		int i = (int) Math.abs((r.nextLong()) % (keysize - 1));
		String keystr = LibRSA.keys[i];
		String[] k = keystr.split(",");
		this.pri_key = new BigInteger(k[0], 16);
		this.pub_key = new BigInteger(k[1], 16);
	}

	public void genKeyPair(int klen)
	{
		BigInteger p = getPrime(klen);
		BigInteger q = getPrime(klen);
		BigInteger one = BigInteger.ONE;
		BigInteger p1 = p.subtract(one);
		BigInteger q1 = q.subtract(one);
		BigInteger p1q1 = p1.multiply(q1);
		BigInteger d = BigInteger.ZERO;
		BigInteger x = BigInteger.ONE;
		boolean success = true;
		while (d.compareTo(BigInteger.ZERO) == 0)
		{
			BigInteger xp1q1 = x.multiply(p1q1);
			BigInteger xp1q1a1 = xp1q1.add(one);
			BigInteger xp1q1a1re = xp1q1a1.remainder(e);
			if (xp1q1a1re.compareTo(BigInteger.ZERO) == 0)
			{
				d = xp1q1a1.divide(e);
			}
			x = x.add(one);
			if (x.compareTo(BigInteger.valueOf(10)) == 1)
			{
				success = false;
				break;
			}
		}
		if (success)
		{
			pub_key = p.multiply(q);
			pri_key = d;
		}
		else
		{
			genKeyPair(klen);
		}
	}

	private BigInteger getPrime(int klen)
	{
		Random rdm = new Random();
		return BigInteger.probablePrime(klen, rdm);
	}

	public String getPrivate()
	{
		return pri_key.toString(radix);
	}

	public String getPublic()
	{
		return pub_key.toString(radix);
	}

	/**
	 * Encode a string using the private key text - the string to encode, e.g.
	 * "hello world"
	 */
	public String privateEncode(String message)
	{
		String result = "";
		// String message = URLEncoder.encode(text, "utf-8");
		// System.out.println(message);
		int length = message.length();
		for (int i = 0; i < length; i += chunk_size)
		{
			String str = message.substring(i, i + chunk_size > length ? length : i + chunk_size);
			byte[] value = str.getBytes();
			BigInteger bi = new BigInteger(1, value);
			/*
			 * System.out.println("Debug: '" + str + "' converted to BigInteger
			 * is " + bi.toString(16));
			 */
			BigInteger tc = bi.modPow(pri_key, pub_key);
			if (result.length() > 0)
				result += cipher_delimiter;
			result += tc.toString(radix);
		}
		return result;
	}

	public String privateDecode(String cipher)
	{
		String result = "";
		String strs[] = cipher.split(cipher_delimiter);
		for (int i = 0; i < strs.length; i++)
		{
			BigInteger bi = new BigInteger(strs[i], radix);
			BigInteger tc = bi.modPow(pri_key, pub_key);
			/*
			 * System.out.println("Debug: '" + strs[i] + "' decoded to
			 * BigInteger is " + tc.toString(16));
			 */
			result += new String(tc.toByteArray());
		}
		return result;
	}

	public String hashEncode(String strText, String hkey)
	{
		String encText = "";
		int pwLength = hkey.length();
		int i = 0;
		int strlength = strText.length();
		for (int x = 0; x < strlength; x++)
		{
			if (x > 0)
				encText += cipher_delimiter;
			i = (i % pwLength) + 1;
			// encText += (Number(strText.charCodeAt(x) ^
			// hkey.charCodeAt(i-1)));\
			int a = (strText.charAt(x) ^ hkey.charAt(i - 1));
			// System.out.println(x + ":" + a);
			encText += a;
		}
		return encText;
	}

	public String hashDecode(String encText, String hkey) throws Exception
	{
		String strText = "";
		int pwLength = hkey.length();
		String[] crypt = encText.split(cipher_delimiter);
		int i = 0;
		int cryptlength = crypt.length;
		for (int x = 0; x < cryptlength; x++)
		{
			i = (i % pwLength) + 1;
			int hold = Integer.parseInt(crypt[x]) ^ hkey.charAt(i - 1);
			char a = (char) hold;
			// System.out.println(x + ":" + a + " -- hold: " + hold);
			strText += a;
		}
		return strText;
	}

	public void genHashKey(int keylen)
	{
		String keystr = "";
		for (int i = 0; i < keylen; i++)
		{
			double a = Math.random() * 100000000;
			int rndNum = (int) (a % 94) + 33;
			char textChar = (char) rndNum;
			keystr += textChar;
		}
		this.hashKey = keystr;
	}

	public String getHashKey()
	{
		return this.hashKey;
	}

	public void setPublicKey(String publicKey)
	{
		this.pub_key = new BigInteger(publicKey, 16);
	}

	public void setPrivateKey(String privateKey)
	{
		this.pri_key = new BigInteger(privateKey, 16);
	}
}
